// timeline.js v0, Fri Aug 8 2008

// Copyright (c) 2008-2009 Jared Grippe (http://openchron.org, http://ourpa.st)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// For details, see the openchron.org web site: http://openchron.org/

Object.extend(Event,{
  observeNext: function(element, eventName, handler) {
    var wrapper = function() {
      Event.stopObserving(element, eventName, wrapper);
      handler.apply(element, arguments);
    }
    Event.observe(element, eventName, wrapper);
    return element;
  },
  wheel:function (event){
    var delta = 0;
    if (!event) event = window.event;
    if (event.wheelDelta) {
      delta = event.wheelDelta/120;
      if (window.opera) delta = -delta;
    } else if (event.detail) { 
      delta = -event.detail/3;     
    }
    return Math.round(delta); //Safari Round
  }
});

Element.addMethods({
  observeNext: Event.observeNext
});

Element.Class = function(){
  var constructor = null, initialize = Prototype.emptyFunction, properties = $A(arguments);
  if (Object.isString(properties[0]))
    constructor = Element.curry(properties.shift())

  if (Object.isFunction(properties[0]))
    constructor = properties.shift()

  if (!constructor)
    constructor = Element.curry('div')

  methods = properties.shift()
    
  if (methods.initialize)
    initialize = methods.initialize
  
  delete methods.initialize

  function klass() {
    var element = $(constructor());
    if (!Object.isElement(element))
      throw new Error('Element.class constructor must return DOM Element')
    Object.extend(element,methods)
    initialize.apply(element, arguments)
    return element
  }

  return klass;
}



/*
 * TIME LINE
 * 
 *
 */

var Timeline = {
 Version: '0',
 REQUIRED_PROTOTYPE: '1.6.0'
}

Timeline = Object.extend(Class.create((function(){

 /**
  * Creates a DIV with added methods to be used as a "stage" for all the points
  * on the timeline
  *
  * The Stage object houses all the code that controlls
  * - Dragging
  * - Zooming
  *
  * @param timeline a timeline object
  */
  var Stage = Element.Class((function(){
    return {
      initialize: function(timeline){
        this.timeline = timeline;
        this
          .addClassName('timeline_stage')
          .setStyle({
            position:'absolute',
            top: 0,
            left: 0,
            background: 'blue url(http://www.cnms.ornl.gov/nanosci/lp/lp2_Carbon_nanotube_pattern-hexagon-circles.jpg) repeat 0 0'
          })
          .observe('mousedown',startSliding.bind(this))
      },
      slide: function(shift,animate) {
        var oldLeft = parseInt(this.style.left) || 0;
        var newLeft = oldLeft+(shift||0);
        if (oldLeft != newLeft) this.slideTo(newLeft,animate);
        return this;
      },
      slideTo: function(newLeft,animate) {
        var maxLeft = (this.clientWidth - this.timeline.window.clientWidth) * -1
        newLeft = (newLeft > 0)? 0 : (newLeft < maxLeft)? maxLeft : newLeft;
        if(animate){
         if (this._slideEffect) this._slideEffect.cancel();
         this._slideEffect = new Effect.Morph(this,{
           style: 'left: '+newLeft+'px',
           duration: 0.5
         })
        }else{
          this.style.left = newLeft+'px';
        }
      }
    };

    function startSliding(event){
      if (!Event.isLeftClick(event)) return false;

      Event.stop(event);
      var startPointerX = Event.pointerX(event);

      var slide = function(event) {      
        var newPointerX = Event.pointerX(event);
        this.slide(newPointerX - startPointerX);
        startPointerX = newPointerX;
      }.bindAsEventListener(this);

      Event.observe(document,'mousemove', slide)
      Event.observeNext(document, 'mouseup', function(event) {
        Event.stopObserving(document,'mousemove', slide);
      });
    }

  })())
  
  

  
  
  
// Timeline Object
  return {
    initialize : function(container){
      this.container = $(container)
      this.events = []
      
      //This is a wrapper that allows the syntaxt: new MyTimeline.Event(data)
      this.Event = function(data){ return new Timeline.Event(this, data) }.bind(this)
      
    },
 
   /**
    * Creates the elements that makeup the Timeline
    */
    draw: function(){ return this.redraw() },
    redraw: function(){
      this.container
      if (this.container.getStyle('position') == 'static')
        this.container.setStyle({position:'relative'})
      
      this.window = new Element('div')
        .addClassName('timeline_window')
        .setStyle({
          position:'absolute',
          top: 0,
          left: 0,
          width: '100%',
          height: '100%',
          overflow: 'hidden',
          backgroundColor: 'red'
        })
      
      this.container.update(this.window) 

      this.stage = new Stage(this).setStyle({
        // width: this.window.clientWidth+'px',
        // width: '1200px',
        width: '100%',
        // height: this.window.clientHeight+'px',
        height: '100%'
      })
      
      this.window.insert(this.stage)
      return this
    },

    
    
  }

  /* Private Methods */
  function privateMethod() {

  }
  
})()),Timeline);

Timeline.Event = Class.create({
  initialize : function(timeline, data){
    this.timeline = timeline;
    timeline.events.push(this)
    Object.extend(this, data)
    this.redraw()
  },
  redraw: function(){
    this.point = new Element('div').setStyle({
      position:'absolute',
      height: '1px',
      width: '1px',
      top: '50%',
      left: '50%',
      backgroundColor: 'yellow'
    })
    this.content = new Element('div').setStyle({
      position:'absolute',
      height: '9px',
      width: '9px',
      top: '-4.5px',
      left: '-4.5px',
      background: 'url(http://i.pbase.com/o4/56/646456/1/57064352.star.gif) no-repeat top left'
    })
    this.timeline.stage.insert(this.point)
    this.point.update(this.content)
  }
});











